package com.wangyb.wework.utils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.ruoyi.common.utils.http.HttpUtils;
import com.wangyb.wework.bo.ContactAddwayState;
import com.wangyb.wework.enums.RespErrCodeEnum;
import com.wangyb.wework.entity.agent.WwAgent;
import com.wangyb.wework.exception.CommonException;
import com.wangyb.wework.wxApi.*;
import okhttp3.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.io.File;
import java.util.Set;

import static com.wangyb.wework.common.WxApiConst.*;


/**
 * @Author: wangyb
 * @Date: 2021/6/25 9:12 上午
 */
@Component
public class WxApiUtils {
	private static final Logger log = LoggerFactory.getLogger(WxApiUtils.class);
	private static final String CONST_ACCESS_TOKEN_INVALID = "-1";
	/**
	 * 获取部门列表
	 *
	 * @param corpId 企业 id
	 * @return 部门列表 json
	 */
	public static String requestDepartmentListApi(Long corpId) {
		String accessToken = WxTokenUtils.getAccessTokenEmployee(corpId);
		String key = "department";
		String respJson = doGetResult(API_DEPARTMENT_LIST,accessToken,null,key);
		if (CONST_ACCESS_TOKEN_INVALID.equals(respJson)) {
			accessToken = WxTokenUtils.getNewAccessTokenEmployee(corpId);
			respJson = doGetResult(API_DEPARTMENT_LIST,accessToken,null,key);
		}
		return respJson;
	}
	/**
	 * 获取部门员工列表
	 *
	 * @param corpId         企业 id
	 * @param wxDepartmentId 企业微信部门 id
	 * @return 员工列表 json
	 */
	public static String requestUserListApi(Long corpId, Long wxDepartmentId) {
		String accessToken = WxTokenUtils.getAccessTokenEmployee(corpId);
		String key = "userlist";
		JSONObject params = new JSONObject();
		params.put("department_id",wxDepartmentId);
		params.put("fetch_child",0);
		String respJson = doGetResult(API_USER_LIST,accessToken,params,key);
		if (CONST_ACCESS_TOKEN_INVALID.equals(respJson)) {
			accessToken = WxTokenUtils.getNewAccessTokenEmployee(corpId);
			respJson = doGetResult(API_USER_LIST,accessToken,params,key);
		}
		return respJson;
	}
	/**
	 * 获取员工详情
	 *
	 * @param agent   应用
	 * @param code    通过成员授权获取到的code
	 * @return 员工列表 json
	 */
	public static String requestWxUserIdApi(Long corpId, WwAgent agent, String code) {
		String accessToken = WxTokenUtils.getAccessTokenAgent(corpId, agent);
		String url = API_USER_INFO
			+ "?access_token=" + accessToken
			+ "&code=" + code;
		JSONObject params = new JSONObject();
		params.put("code",code);
		String key = "UserId";
		String respJson = doGetResult(API_USER_INFO,accessToken,params,key);
		if (CONST_ACCESS_TOKEN_INVALID.equals(respJson)) {
			url = API_USER_LIST
				+ "?access_token=" + WxTokenUtils.getNewAccessTokenAgent(corpId, agent).getAccessToken()
				+ "&code=" + code;
			respJson = doGetResult(API_USER_INFO,accessToken,params,key);
		}
		return respJson;
	}
	/**
	 * 获取开启外部联系人权限的微信员工 id 列表
	 *
	 * @param corpId 企业 id
	 * @return 开启外部联系人权限的微信员工 id 列表 json
	 */
	public static String requestFollowUserListApi(Long corpId) {
		String accessToken = WxTokenUtils.getAccessTokenContact(corpId);
		String key = "follow_user";
		String respJson = doGetResult(API_FOLLOW_USER_LIST,accessToken,null,key);
		if (CONST_ACCESS_TOKEN_INVALID.equals(respJson)) {
			accessToken = WxTokenUtils.getNewAccessTokenContact(corpId);
			respJson = doGetResult(API_FOLLOW_USER_LIST,accessToken,null,key);
		}
		return respJson;
	}

	/**
	 * 配置客户联系「联系我」方式  自动拉群
	 * https://work.weixin.qq.com/api/doc/90000/90135/92572
	 * @param corpId
	 * @param skipVerify
	 * @param state
	 * @param wxUserIdSet
	 * @return
	 */
	public static CreateContactWayResp requestCreateContactWay(Long corpId, boolean skipVerify, ContactAddwayState state, Set<String> wxUserIdSet) {
		String accessToken = WxTokenUtils.getAccessTokenContact(corpId);
		JSONObject params = new JSONObject();
		params.put("type", "2");
		params.put("scene", "2");
		params.put("skip_verify", skipVerify);
		//TODO state.toString()后 wrong json format,需要重新处理
		params.put("state", state);
		params.put("user", wxUserIdSet);
		CreateContactWayResp resp = doPost(CreateContactWayResp.class, accessToken, params);
		return resp;
	}
	/**
	 * 配置客户联系「联系我」方式  自动拉群
	 * https://work.weixin.qq.com/api/doc/90000/90135/92572
	 * @param corpId
	 * @param configId
	 * @param skipVerify
	 * @param wxUserIdSet
	 * @return
	 */
	public static BaseWxResp requestUpdateContactWay(Long corpId,String configId, boolean skipVerify, Set<String> wxUserIdSet) {
		String accessToken = WxTokenUtils.getAccessTokenContact(corpId);
		JSONObject params = new JSONObject();
		params.put("config_id",configId);
		params.put("skip_verify", skipVerify);
		params.put("type", "2");
		params.put("scene", "2");
		params.put("user", wxUserIdSet);
		BaseWxResp resp = doPost(API_UPDATE_CONTACT_WAY, accessToken, params);
		return resp;
	}

	/**
	 * 获取企业已配置的「联系我」方式
	 * @param corpId
	 * @param configId
	 * @return
	 */
	public static BaseWxResp requestGetContactWay(Long corpId,String configId){
		String accessToken = WxTokenUtils.getAccessTokenContact(corpId);
		JSONObject params = new JSONObject();
		params.put("config_id",configId);
		BaseWxResp resp = doPost(API_GET_CONTACT_WAY,accessToken,params);
		return resp;
	}
	/**
	 * 删除企业已配置的「联系我」方式
	 * @param corpId
	 * @param configId
	 * @return
	 */
	public static BaseWxResp requestDelContactWay(Long corpId,String configId){
		String accessToken = WxTokenUtils.getAccessTokenContact(corpId);
		JSONObject params = new JSONObject();
		params.put("config_id",configId);
		BaseWxResp resp = doPost(API_DEL_CONTACT_WAY,accessToken,params);
		return resp;
	}

	/**
	 * 获取员工客户相关统计数据
	 *
	 * @param corpId   企业 id
	 * @param wxUserId 微信员工 id
	 * @return 员工客户相关统计数据 json
	 */
	public static UserBehaviorDataResp getUserBehaviorData(Long corpId, String wxUserId,Long startTime,Long endTime) {
		String accessToken = WxTokenUtils.getAccessTokenContact(corpId);
		JSONObject params = new JSONObject();
		params.put("userid", new String[]{wxUserId});
		params.put("start_time", startTime);
		params.put("end_time", endTime);
		UserBehaviorDataResp resp = doPost(UserBehaviorDataResp.class, accessToken, params);
		return resp;
	}
	/**
	 * 获取客户列表
	 *
	 * @param corpId
	 * @return
	 */
	public static String getExternalContactList(Long corpId, String wxUserId) {
		String accessToken =  WxTokenUtils.getAccessTokenContact(corpId);
		String key = "external_userid";
		JSONObject params = new JSONObject();
		params.put("userid",wxUserId);
		String respJson = doGetResult(API_GET_EXTERNAL_LIST,accessToken,params,key);
		if (CONST_ACCESS_TOKEN_INVALID.equals(respJson)) {
			accessToken = WxTokenUtils.getNewAccessTokenContact(corpId);
			respJson = doGetResult(API_GET_EXTERNAL_LIST,accessToken,params,key);
		}
		return respJson;
	}

	/**
	 * 获取客户详情
	 *
	 * @param corpId
	 * @return
	 */
	public static ExternalContactResp getExternalContactInfo(Long corpId, String externalUserid) {
		String accessToken =  WxTokenUtils.getAccessTokenContact(corpId);
		JSONObject params = new JSONObject();
		params.put("external_userid",externalUserid);
		ExternalContactResp resp = new ExternalContactResp();
		String respJson = doGetResult(API_GET_EXTERNAL_INFO, accessToken,params,null);
		if (CONST_ACCESS_TOKEN_INVALID.equals(respJson)) {
			accessToken=WxTokenUtils.getNewAccessTokenContact(corpId);
			respJson = doGetResult(API_GET_EXTERNAL_INFO, accessToken,params,null);
		}
		resp.setCorpId(corpId);
		resp.setExternalContact(JSON.parseObject(getRespByJsonKey(respJson,"external_contact")));
		resp.setFollowUser(JSONArray.parseArray(getRespByJsonKey(respJson,"follow_user")));
		resp.setNextCursor(getRespByJsonKey(respJson,"next_cursor"));
		return resp;
	}
	/**
	 * 获取企业标签库
	 *
	 * @param corpId
	 * @return
	 */
	public static CorpTagListResp getTagDetail(Long corpId, String wxTagId) {
		String accessToken =  WxTokenUtils.getAccessTokenContact(corpId);
		JSONObject params = new JSONObject();
		params.put("tag_id",wxTagId);
		CorpTagListResp resp = doPost(CorpTagListResp.class, accessToken, params);
		return resp;
	}

	/**
	 * 获取群列表
	 * @param corpId
	 * @return
	 */
	public static GroupchatListResp getGroupchatList(Long corpId){
		String accessToken =  WxTokenUtils.getAccessTokenContact(corpId);
		GroupchatListResp resp = doGet(GroupchatListResp.class, accessToken, null);
		return resp;
	}

	/**
	 * 获取群详情
	 * @param corpId
	 * @param chatId
	 * @return
	 */
	public static GroupchatResp getGroupchatInfo(Long corpId,String chatId){
		String accessToken =  WxTokenUtils.getAccessTokenContact(corpId);
		JSONObject params = new JSONObject();
		params.put("chat_id",chatId);
		params.put("need_name",1);
		GroupchatResp resp = doPost(GroupchatResp.class, accessToken, params);
		return resp;
	}
	/**
	 * 上传临时素材
	 *
	 * @param corpId 企业 id
	 * @param type 素材文件类型: 分别有图片（image）、语音（voice）、视频（video），普通文件（file）
	 * @param file   素材文件
	 * @return 素材文件 id
	 */
	public static String uploadFileToTemp(Long corpId, String type, File file) {
		log.debug("=================上传文件素材========================");
		String accessToken = WxTokenUtils.getAccessTokenEmployee(corpId);
		String key = "media_id";
		BaseWxResp wxResp = doPost(API_UPLOAD_FILE_TO_TEMP, accessToken,type, file);
		return wxResp.get(key);
	}

	private static <T extends BaseWxResp> T doPost(Class<T> clazz, String accessToken, JSONObject params){
		T response = null;
		try {
			response = clazz.newInstance();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
		String reqUrl = response.reqUrl()+"?access_token="+accessToken;
		log.debug(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ");
		log.debug("url: " + reqUrl);
		String resp = HttpUtils.sendPost(reqUrl,params.toJSONString());
		log.debug("respJson: " + resp);
		log.debug("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ");
		response = JSON.parseObject(resp,clazz);
		response.setJsonString(resp);
		if (response.getErrcode() != 0){
			throw new CommonException(RespErrCodeEnum.THIRD_API_ERROR.getCode(),"调用企业微信错误");
		}
		return response;
	}
	private static BaseWxResp doPost(String reqUrl,String accessToken,JSONObject params){
		String url = reqUrl+"?access_token="+accessToken;
		String resp = HttpUtils.sendPost(url,params.toJSONString());
		BaseWxResp response = JSON.parseObject(resp, BaseWxResp.class);
		response.setJsonString(resp);
		if (response.getErrcode() !=0){
			throw new CommonException(RespErrCodeEnum.THIRD_API_ERROR.getCode(),"调用企业微信错误");
		}
		return response;
	}
	private static BaseWxResp doPost(String reqUrl,String accessToken,String type,File file){
		OkHttpClient client = new OkHttpClient();
		String url = reqUrl+"?access_token="+accessToken+"&type="+type;
		RequestBody requestBody = new MultipartBody.Builder()
			.setType(MultipartBody.FORM)
			.addFormDataPart("file", file.getName(),
				RequestBody.create(MediaType.parse("multipart/form-data"), file))
			.build();
		Request request = new Request.Builder()
//			.header("Authorization", "Client-ID " + UUID.randomUUID())
			.url(url)
			.post(requestBody)
			.build();
		try {
			Response response = client.newCall(request).execute();
			String resp = response.body().string();
			BaseWxResp wxResp = JSON.parseObject(resp, BaseWxResp.class);
			wxResp.setJsonString(resp);
			if (wxResp.getErrcode() !=0){
				throw new CommonException(RespErrCodeEnum.THIRD_API_ERROR.getCode(),"调用企业微信错误");
			}
			return wxResp;
		}catch (Exception e){
			throw new CommonException(RespErrCodeEnum.THIRD_API_ERROR.getCode(),"调用企业微信发生错误");
		}
	}
	private static <T extends BaseWxResp> T doGet(Class<T> clazz, String accessToken, JSONObject params){
		T response = null;
		try {
			response = clazz.newInstance();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
		String reqUrl = response.reqUrl();
		log.debug(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ");
		log.debug("url: " + reqUrl);
		if (params == null){
			params = new JSONObject();
		}
		params.put("access_token",accessToken);
		String resp = HttpUtils.sendGet(reqUrl, getQueryString(params));
		log.debug("respJson: " + resp);
		log.debug("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ");
		response = JSON.parseObject(resp,clazz);
		response.setJsonString(resp);
		return response;
	}

	private static String doGetResult(String url,String accessToken,JSONObject params,String key){
		log.debug(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ");
		log.debug("url: " + url);
		if (params == null){
			params = new JSONObject();
		}
		params.put("access_token",accessToken);
		String resp = HttpUtils.sendGet(url, getQueryString(params));
		log.debug("respJson: " + resp);
		log.debug("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ");
		if (key != null){
			return getRespByJsonKey(resp,key);
		}else{
			return resp;
		}
	}

	private static String getQueryString(JSONObject json){
		StringBuffer sb = new StringBuffer();
		json.keySet().forEach(k->{
			sb.append(k);
			sb.append("=");
			sb.append(json.get(k));
			sb.append("&");
		});
		return sb.toString();
	}



	public static String getRespByJsonKey(String resp,String key){
		log.debug(key + " : " + resp);

		JSONObject jsonObject = JSON.parseObject(resp);
		int errCode = jsonObject.getIntValue("errcode");
		if (errCode == 42001) {
			return CONST_ACCESS_TOKEN_INVALID;
		}
		if (errCode == 0) {
			if (key == null) {
				return "";
			} else if (key.isEmpty()) {
				return resp;
			} else {
				return jsonObject.getString(key);
			}
		}
		return null;
	}
}
